package be.kul.osgi.ds.myagent.Role;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
import java.util.zip.ZipOutputStream;

import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.core.runtime.FileLocator;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleReference;
import org.osgi.framework.ServiceReference;
import org.xml.sax.SAXException;

import be.kul.osgi.ds.irole.IRole;
import be.kul.osgi.ds.irole.ITask;
import be.kul.osgi.ds.myagent.MyAgent;
import be.kul.osgi.ds.myagent.ZipUsingJavaUtil;

public class RoleHandler {

	IRole r;
	MyAgent agent;
	
	public RoleHandler(IRole role, MyAgent a){
		this.r = role;
		this.agent = a;
	}
	
	public String getBundlePath() throws IOException {
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		String path = FileLocator.getBundleFile(bundle).getAbsolutePath();
        System.out.println("bundlepath role: "+ path);
		return path;
	}
	
	public String getResourcePath() throws IOException, URISyntaxException {
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		URL urlpath = bundle.getResource("/");
        File f = new File(FileLocator.toFileURL(urlpath).toURI());
        String path = f.getAbsolutePath();
        System.out.println("bundlepath resources: "+ path);
		return path;
	}
	
	public String getBundleDataPath(){
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		String path = bundle.getDataFile("").getAbsolutePath();
        System.out.println("bundledatapath role : "+ path);
		return path;
	}
	
	public String getBundleMetaPath() throws URISyntaxException, IOException{
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		URL data = bundle.getResource("/META-INF/");
	    File g = new File(FileLocator.toFileURL(data).toURI());  
	    String path = g.getAbsolutePath();
	    System.out.println("META-INF path role : "+ path);
		return path;
	}
	
	public String getBundleComponentpath() throws URISyntaxException, IOException{
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		URL data = bundle.getResource("/OSGI-INF/");
	    File g = new File(FileLocator.toFileURL(data).toURI());  
	    String path = g.getAbsolutePath();
	    System.out.println("OSGI-INF path role : "+ path);
		return path;
	}
	
	public String getSymbolicName() {
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		bundle.getSymbolicName();
		return bundle.getSymbolicName();
	}
	
	public void reInit()
	{
		r.reInit();
	}

	
	public String getfeatures() throws IOException, URISyntaxException {
		Properties properties = new Properties();
		//Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		InputStream input = r.getClass().getResourceAsStream("role.properties");
		properties.load(input);
		return properties.toString();
	}
	
	
	/*
	 * Serializing and deserializing a Propertiesobject must go through the Propertiesfunctions itself and not by XStream.
	 * Because the Properties Object handles another XML format than XStream.
	 */
	
	public String SerializeFeatures() throws IOException {
		Properties properties = new Properties();
		//Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		InputStream input = r.getClass().getResourceAsStream("role.properties");
		properties.load(input);
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
			try
			{
				properties.storeToXML(byteArrayOutputStream, null);
				String xmlString = byteArrayOutputStream.toString();
				//System.out.println(xmlString);
				return xmlString;
			} catch(Exception e){
				e.printStackTrace();
			}
			
		//return service.toXML(properties);
		return null;
	
	}
	
	public Properties deSerializeFeatures(String xml) throws InvalidPropertiesFormatException, IOException {
		Properties properties = new Properties();
		InputStream is = new ByteArrayInputStream(xml.getBytes());
		properties.loadFromXML(is);
		return properties;
	}
	
	public void exportState() {
		// TODO Auto-generated method stub
		//agent.XMLStreamservice.export(r.getState(), getBundleDataPath() + File.separator +"state.xml");
	}
	
	public void importState() {
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		URL data = bundle.getResource("/state/state.xml");
		File g;
		String path ;
		try {
			g = new File(FileLocator.toFileURL(data).toURI());
			path = g.getAbsolutePath();
			//r.setState(agent.XMLStreamservice.readFile(path, r.getState().getClass()));
			//System.out.println("ReInit : " + r.getState());
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
	}
	
	public boolean sellRole(String receiver)
	{
		//time-out is 5000ms
		//
		String content = "";
		try {
			content = SerializeFeatures();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		//first try to sell the role
		//ContractInitiator ci = new ContractInitiator(null,null,null);
		//second : export the state of the role
		exportState();
		//third : pack up the role and publish it
		String filename = null;
		try {
			filename = agent.serverservice.publish(agent.bundledata, pack(agent.bundledata));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//ContractInitiator ci = new ContractInitiator(agent, content,receiver, "link");
		//ci.doCFP();
		String link = "http://localhost/files/" + filename;
		//agent.messagehandler.ci.set(content, receiver, link);
		//agent.messagehandler.ci.doCFP();
		return false;
	}
	
	public String pack(String tempdir){
		
		try {
			ZipUsingJavaUtil zipclass= new ZipUsingJavaUtil();
			FileOutputStream fileWriter = new FileOutputStream(tempdir + File.separator + getSymbolicName() + ".zip");
			ZipOutputStream zip = new ZipOutputStream(fileWriter);

			zipclass.addSubFoldersToZip("", getResourcePath(), zip);
			zipclass.addFileToZip("META-INF", getBundleMetaPath() + File.separator + "MANIFEST.MF", zip,false);
			zipclass.addFolderToZip("", getBundleComponentpath(), zip);
			zipclass.addFileToZip("state", getBundleDataPath() + File.separator + "state.xml", zip,false);
			
			zip.flush();
			zip.close();
			return getSymbolicName() + ".zip";
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
		return null;
	}		
	
	public String packBundle(String tempdir){
		
		try {
			ZipUsingJavaUtil zipclass= new ZipUsingJavaUtil();
			FileOutputStream fileWriter = new FileOutputStream(tempdir + File.separator + getSymbolicName() + ".zip");
			ZipOutputStream zip = new ZipOutputStream(fileWriter);

			zipclass.addSubFoldersToZip("", getResourcePath(), zip);
			zipclass.addFileToZip("META-INF", getBundleMetaPath() + File.separator + "MANIFEST.MF", zip,false);
			zipclass.addFolderToZip("", getBundleComponentpath(), zip);
			//zipclass.addFileToZip("state", getBundleDataPath() + File.separator + "state.xml", zip,false);
			
			zip.flush();
			zip.close();
			return getSymbolicName() + ".zip";
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
		return null;
	}
	
	public long getDue() throws IOException
	{
		Properties properties = new Properties();
		//Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		InputStream input = r.getClass().getResourceAsStream("role.properties");
		properties.load(input);
		long l = Long.parseLong(properties.getProperty("due"));
		return l;
	}
	
	public long getTime() throws IOException{
		Properties properties = new Properties();
		//Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		InputStream input = r.getClass().getResourceAsStream("role.properties");
		properties.load(input);
		long l = Long.parseLong(properties.getProperty("time"));
		return l;
	}
	
	public String getDependenciesXML(){
		String s = "";
		ArrayList<Bundle> a = this.getDependencies();
		if (!a.isEmpty()){
			for (Bundle b:a){
				s = s + "<Dependency>" + b.getSymbolicName() + "</Dependency>"; 
			}
			return "<Dependencies>" + s +"</Dependencies>";
		}
		return null;
	}
	
	public ArrayList<Bundle> getDependencies() {
		
		Bundle bundle = BundleReference.class.cast(r.getClass().getClassLoader()).getBundle();
		
		ArrayList<Bundle> bundles = new ArrayList<Bundle>();
		
		RecursDeps(bundle, bundles);
		
		for(int i = 0; i < bundles.size(); i++){
			System.out.println("services in use : "+bundles.get(i).getSymbolicName());
		}
		
		return bundles;
	}
	
	public void RecursDeps(Bundle b, ArrayList<Bundle> l){
		ServiceReference<?>[] deps = b.getServicesInUse();
		
		if (deps != null){
			int size = deps.length;
			
			for (int i = 0; i < size; i++){
				Bundle btest = deps[i].getBundle();
				if(!l.contains(btest)){
					l.add(btest);
					RecursDeps(btest, l);
				}
			}
		}
	}
	
	/*
	 * Given the bundle name, it searches and if found the function returns true
	 * Otherwist it return false.
	 */
	public boolean RoleLookup(String SymName){
		Bundle[] bundles = agent.context.getBundles();
		for(int j = 0; j < bundles.length; j++){
			if (SymName.equals(bundles[j])){
				return true;
			}
		}
		return false;
	}
	
	
	/*
	 * Given the bundle name, it searches and gives back the bundle.
	 * Otherwist it return null.
	 */
	public Bundle getBundle(String SymName){
		Bundle[] bundles = agent.context.getBundles();
		for(int j = 0; j < bundles.length; j++){
			if (SymName.equals(bundles[j])){
				return bundles[j];
			}
		}
		return null;
	}
	
	//returns an arraylist of all the tasks in of a Role
	public ArrayList<ITask> getTasks(){
		return r.getTasks();
	}
	
	
	//serializes a task to xml format
	public String serializeTask(){
		ArrayList<ITask> ttasks = getTasks();
		if(!ttasks.isEmpty()){
			int size = ttasks.size();
			agent.XMLStreamservice.export(ttasks.get(0), getBundleDataPath() + File.separator +"task.xml");
			try {
				agent.serverservice.publish(getBundleDataPath(),"task.xml");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return "string";
	}
	
	
	public void importTask(URL url, Class clazz){
		agent.XMLStreamservice.readFile(url, clazz);
	}
	
	public void SellTasks(){
		ArrayList<ITask> tasks = getTasks();
		for(ITask t:tasks){
			(new TaskHandler(this.agent)).shareTask(t,this.r);
		}
		
	}
	
	public void getValue(URL taskxml, String value){
		//
	}
	
	public void getRoot(URL taskxml){
		try {
			String x = agent.XMLStreamservice.getRoot(taskxml);
			//System.out.println(x);
			
			String y = "Task";
			int index = x.lastIndexOf(y);
			String pack = x.substring(0, index-1);
			
			//System.out.println(pack);
			getDependencies();
			//System.out.println(r.getClass().getName());
			//agent.context.getServiceReference("be.kul.osgi.ds.role1.Role").getBundle();
			//agent.context.
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void getDue2(String taskxml){
		try {
			String x = agent.XMLStreamservice.getDue(taskxml);
			//System.out.println(x);
		
			
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
